package navi;

import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import com.sun.tools.attach.spi.AttachProvider;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.util.Properties;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

/**
 * Startup class for remote appdomain
 * @author Ivan
 */
public class JAppDomainRemoteKick implements Runnable
{
    public static String parentpid;
    public static String parentcomm;
    public static String FileSeparator;
    public static String childpid;

    public static void main(String []argv)
    {
        JAppDomainRemoteKick kick=new JAppDomainRemoteKick();
        kick.start();
    }
    
    public void start()
    {
        try {       
            FileSeparator = System.getProperty("file.separator");
            String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
            childpid=processName.split("@")[0];
            parentpid=System.getProperty("jappdomain.parentpid");
            parentcomm=System.getProperty("jappdomain.parentcomm");
            notifyParent();
            new Thread(this).start();
            Thread.sleep(Long.MAX_VALUE);
        } catch (Exception ex) {
            Logger.getLogger(JAppDomainRemoteKick.class.getName()).log(Level.SEVERE, null, ex);
        }
        
    }
    
    @Override
    public void run()
    {
        while (true)
        {
            try
            {
                if (!isProcessWithPidAlive(parentpid)) Runtime.getRuntime().exit(0);
                Thread.sleep(1000);
            }
            catch (Exception ex)
            {            
            }        
        }
    }
    
    /**
     * Notify parent about my PID
     */
    public static void notifyParent()
    {
        try {
            final AttachProvider attachProvider = AttachProvider.providers().get(0);
            VirtualMachineDescriptor descriptor = null;
            for (VirtualMachineDescriptor virtualMachineDescriptor : attachProvider.listVirtualMachines()) {
                String id = virtualMachineDescriptor.id();
                if (id.equals(parentpid)) {
                    descriptor = virtualMachineDescriptor;
                    break;
                }
            }
            if (descriptor == null) {
                throw new RuntimeException("Not attached");
            }
            //connect tio JVM JMC
            final VirtualMachine virtualMachine = attachProvider.attachVirtualMachine(descriptor);
            Properties props = virtualMachine.getSystemProperties();
            String home = props.getProperty("java.home");
            String agent = home + FileSeparator + "lib" + FileSeparator + "management-agent.jar";
            virtualMachine.loadAgent(agent, "com.sun.management.jmxremote");
            final Object portObject = virtualMachine.getAgentProperties().get("com.sun.management.jmxremote.localConnectorAddress");
            final JMXServiceURL target = new JMXServiceURL(portObject + "");
            final JMXConnector connector = JMXConnectorFactory.connect(target);
            MBeanServerConnection remotetoparent = connector.getMBeanServerConnection();
            ObjectName name = new ObjectName("navi:type=" + parentcomm);
            ParentCommMBean parentproxy = MBeanServerInvocationHandler.newProxyInstance(remotetoparent, name, ParentCommMBean.class, false);
            parentproxy.NotifyAboutChildPid(childpid);            
        } catch (Exception ex) {
            Logger.getLogger(JAppDomainRemoteKick.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    /**
     * Test if process with PID is alive
     * @param pid
     * @return 
     */
    public static boolean isProcessWithPidAlive(String pid)
    {
        try {
            Process testprocess = Runtime.getRuntime().exec("TASKLIST /FO CSV");
            InputStreamReader tr = new InputStreamReader(testprocess.getInputStream());
            BufferedReader bsr = new BufferedReader(tr);
            String l;
            String fnds=",\""+pid+"\",";
            boolean fnd=false;
            while ((l=bsr.readLine())!=null)
            {
                if (l.contains(fnds)) fnd=true;
            }
            testprocess.destroy();
            return fnd;
        } catch (Exception ex) {
            return false;
        }
    }
    
}
